const { User, PointsTransaction, sequelize } = require('../models')
const { Op } = require('sequelize')
const logger = require('../utils/logger')
const PointsService = require('./pointsService')

class ExpirationService {
  /**
   * 检查并处理过期积分
   * @param {Date} beforeDate - 检查此日期之前的过期积分，默认为当前时间
   * @returns {Promise<Object>} 处理结果
   */
  static async processExpiredPoints(beforeDate = new Date()) {
    const transaction = await sequelize.transaction()
    
    try {
      logger.info(`开始处理过期积分，截止时间: ${beforeDate.toISOString()}`)

      // 查找所有过期的积分记录
      const expiredRecords = await PointRecord.findAll({
        where: {
          type: 'earn',
          expire_at: {
            [Op.lt]: beforeDate
          }
        },
        include: [{
          model: User,
          as: 'user',
          attributes: ['id', 'nickname', 'phone', 'points']
        }],
        transaction
      })

      if (expiredRecords.length === 0) {
        await transaction.commit()
        logger.info('没有找到过期的积分记录')
        return {
          processedCount: 0,
          totalExpiredPoints: 0,
          affectedUsers: 0,
          details: []
        }
      }

      // 按用户分组处理过期积分
      const userExpiredPoints = new Map()
      
      expiredRecords.forEach(record => {
        const userId = record.user_id
        const points = parseFloat(record.points)
        
        if (!userExpiredPoints.has(userId)) {
          userExpiredPoints.set(userId, {
            user: record.user,
            expiredPoints: 0,
            expiredRecords: []
          })
        }
        
        const userData = userExpiredPoints.get(userId)
        userData.expiredPoints += points
        userData.expiredRecords.push(record)
      })

      const processDetails = []
      let totalExpiredPoints = 0

      // 逐个用户处理过期积分
      for (const [userId, userData] of userExpiredPoints) {
        const { user, expiredPoints, expiredRecords } = userData
        
        // 检查用户当前可用积分
        const currentPoints = parseFloat(user.points)
        const actualExpiredPoints = Math.min(expiredPoints, currentPoints)
        
        if (actualExpiredPoints > 0) {
          // 扣除过期积分
          const newBalance = currentPoints - actualExpiredPoints
          
          await user.update({
            points: Math.max(0, newBalance)
          }, { transaction })

          // 创建过期记录
          await PointRecord.create({
            user_id: userId,
            type: 'expire',
            points: -actualExpiredPoints,
            balance: Math.max(0, newBalance),
            description: `积分过期扣除 (${expiredRecords.length}条记录)`
          }, { transaction })

          processDetails.push({
            userId: userId,
            nickname: user.nickname,
            phone: user.phone,
            expiredPoints: actualExpiredPoints,
            expiredRecordsCount: expiredRecords.length,
            balanceBefore: currentPoints,
            balanceAfter: Math.max(0, newBalance)
          })

          totalExpiredPoints += actualExpiredPoints
          
          logger.info(`用户 ${userId} 过期积分 ${actualExpiredPoints}，余额从 ${currentPoints} 变为 ${Math.max(0, newBalance)}`)
        }
      }

      await transaction.commit()

      // 清除相关用户的积分缓存
      const userIds = Array.from(userExpiredPoints.keys())
      await PointsService.refreshPointsCache(userIds)

      const result = {
        processedCount: expiredRecords.length,
        totalExpiredPoints: totalExpiredPoints,
        affectedUsers: processDetails.length,
        details: processDetails
      }

      logger.info(`积分过期处理完成: 处理了 ${result.processedCount} 条记录，影响 ${result.affectedUsers} 个用户，总计过期积分 ${result.totalExpiredPoints}`)

      return result
    } catch (error) {
      await transaction.rollback()
      logger.error('处理过期积分失败:', error)
      throw error
    }
  }

  /**
   * 获取即将过期的积分记录
   * @param {Date} beforeDate - 检查此日期之前即将过期的积分
   * @param {number} days - 提前多少天提醒，默认7天
   * @returns {Promise<Array>} 即将过期的积分记录
   */
  static async getExpiringPoints(beforeDate = null, days = 7) {
    try {
      if (!beforeDate) {
        beforeDate = new Date()
        beforeDate.setDate(beforeDate.getDate() + days)
      }

      const expiringRecords = await PointRecord.findAll({
        where: {
          type: 'earn',
          expire_at: {
            [Op.between]: [new Date(), beforeDate]
          }
        },
        include: [{
          model: User,
          as: 'user',
          attributes: ['id', 'nickname', 'phone']
        }],
        order: [['expire_at', 'ASC']]
      })

      // 按用户分组
      const userExpiringPoints = new Map()
      
      expiringRecords.forEach(record => {
        const userId = record.user_id
        const points = parseFloat(record.points)
        
        if (!userExpiringPoints.has(userId)) {
          userExpiringPoints.set(userId, {
            user: record.user,
            totalExpiringPoints: 0,
            records: [],
            nearestExpireTime: record.expire_at
          })
        }
        
        const userData = userExpiringPoints.get(userId)
        userData.totalExpiringPoints += points
        userData.records.push(record)
        
        // 更新最近过期时间
        if (record.expire_at < userData.nearestExpireTime) {
          userData.nearestExpireTime = record.expire_at
        }
      })

      const result = Array.from(userExpiringPoints.values()).map(userData => ({
        user: userData.user,
        totalExpiringPoints: userData.totalExpiringPoints,
        recordsCount: userData.records.length,
        nearestExpireTime: userData.nearestExpireTime,
        records: userData.records.slice(0, 5) // 只返回前5条记录
      }))

      logger.info(`查询到 ${result.length} 个用户有即将过期的积分`)

      return result
    } catch (error) {
      logger.error('获取即将过期积分失败:', error)
      throw error
    }
  }

  /**
   * 发送积分过期提醒通知
   * @param {Array} expiringData - 即将过期的积分数据
   * @returns {Promise<Object>} 通知发送结果
   */
  static async sendExpirationNotifications(expiringData) {
    try {
      const notifications = []
      
      for (const userData of expiringData) {
        const { user, totalExpiringPoints, nearestExpireTime } = userData
        
        // 计算剩余天数
        const now = new Date()
        const timeDiff = nearestExpireTime.getTime() - now.getTime()
        const daysRemaining = Math.ceil(timeDiff / (1000 * 3600 * 24))
        
        // 创建通知内容
        const notification = {
          user_id: user.id,
          type: 'expire',
          title: '积分即将过期提醒',
          content: `您有 ${totalExpiringPoints} 积分将在 ${daysRemaining} 天后过期，请及时使用。`,
          extra_data: {
            expiringPoints: totalExpiringPoints,
            expireTime: nearestExpireTime,
            daysRemaining: daysRemaining
          }
        }
        
        notifications.push(notification)
      }

      // 这里应该调用消息服务发送通知
      // 暂时只记录日志
      logger.info(`准备发送 ${notifications.length} 条积分过期提醒通知`)
      
      // TODO: 实际发送通知的逻辑
      // await MessageService.sendBatchNotifications(notifications)

      return {
        sentCount: notifications.length,
        notifications: notifications
      }
    } catch (error) {
      logger.error('发送积分过期提醒失败:', error)
      throw error
    }
  }

  /**
   * 获取积分过期统计报表
   * @param {Date} startDate - 开始日期
   * @param {Date} endDate - 结束日期
   * @returns {Promise<Object>} 过期统计报表
   */
  static async getExpirationReport(startDate, endDate) {
    try {
      // 获取指定时间段内的过期记录
      const expiredRecords = await PointRecord.findAll({
        where: {
          type: 'expire',
          created_at: {
            [Op.between]: [startDate, endDate]
          }
        },
        attributes: [
          [sequelize.fn('DATE', sequelize.col('created_at')), 'date'],
          [sequelize.fn('COUNT', sequelize.col('id')), 'count'],
          [sequelize.fn('SUM', sequelize.fn('ABS', sequelize.col('points'))), 'total_expired_points'],
          [sequelize.fn('COUNT', sequelize.fn('DISTINCT', sequelize.col('user_id'))), 'affected_users']
        ],
        group: [sequelize.fn('DATE', sequelize.col('created_at'))],
        order: [[sequelize.fn('DATE', sequelize.col('created_at')), 'ASC']]
      })

      // 获取总体统计
      const totalStats = await PointRecord.findOne({
        where: {
          type: 'expire',
          created_at: {
            [Op.between]: [startDate, endDate]
          }
        },
        attributes: [
          [sequelize.fn('COUNT', sequelize.col('id')), 'total_records'],
          [sequelize.fn('SUM', sequelize.fn('ABS', sequelize.col('points'))), 'total_expired_points'],
          [sequelize.fn('COUNT', sequelize.fn('DISTINCT', sequelize.col('user_id'))), 'total_affected_users']
        ]
      })

      // 获取用户过期积分排行
      const userExpiredRanking = await PointRecord.findAll({
        where: {
          type: 'expire',
          created_at: {
            [Op.between]: [startDate, endDate]
          }
        },
        attributes: [
          'user_id',
          [sequelize.fn('SUM', sequelize.fn('ABS', sequelize.col('points'))), 'expired_points']
        ],
        include: [{
          model: User,
          as: 'user',
          attributes: ['id', 'nickname', 'phone']
        }],
        group: ['user_id'],
        order: [[sequelize.fn('SUM', sequelize.fn('ABS', sequelize.col('points'))), 'DESC']],
        limit: 10
      })

      const result = {
        period: {
          startDate: startDate,
          endDate: endDate
        },
        summary: {
          totalRecords: parseInt(totalStats?.get('total_records') || 0),
          totalExpiredPoints: parseFloat(totalStats?.get('total_expired_points') || 0),
          totalAffectedUsers: parseInt(totalStats?.get('total_affected_users') || 0)
        },
        dailyStats: expiredRecords.map(record => ({
          date: record.get('date'),
          count: parseInt(record.get('count')),
          expiredPoints: parseFloat(record.get('total_expired_points')),
          affectedUsers: parseInt(record.get('affected_users'))
        })),
        topExpiredUsers: userExpiredRanking.map(record => ({
          user: record.user,
          expiredPoints: parseFloat(record.get('expired_points'))
        }))
      }

      logger.info(`生成积分过期报表: ${result.summary.totalRecords} 条记录，${result.summary.totalExpiredPoints} 积分过期`)

      return result
    } catch (error) {
      logger.error('获取积分过期统计报表失败:', error)
      throw error
    }
  }

  /**
   * 定时任务：处理过期积分
   * 建议每天凌晨执行
   */
  static async scheduledExpiredPointsCleanup() {
    try {
      logger.info('开始执行定时积分过期清理任务')
      
      const result = await this.processExpiredPoints()
      
      logger.info(`定时积分过期清理完成: 处理 ${result.processedCount} 条记录，影响 ${result.affectedUsers} 个用户`)
      
      return result
    } catch (error) {
      logger.error('定时积分过期清理失败:', error)
      throw error
    }
  }

  /**
   * 定时任务：发送积分过期提醒
   * 建议每天执行，提前7天提醒
   */
  static async scheduledExpirationReminder() {
    try {
      logger.info('开始执行定时积分过期提醒任务')
      
      const expiringData = await this.getExpiringPoints(null, 7)
      
      if (expiringData.length > 0) {
        const notificationResult = await this.sendExpirationNotifications(expiringData)
        logger.info(`积分过期提醒发送完成: ${notificationResult.sentCount} 条通知`)
        return notificationResult
      } else {
        logger.info('没有需要提醒的即将过期积分')
        return { sentCount: 0, notifications: [] }
      }
    } catch (error) {
      logger.error('定时积分过期提醒失败:', error)
      throw error
    }
  }
}

module.exports = ExpirationService